#include "SkeletonEncoder.h"

#define FISHEAD_IDENTIFIER "fishead\0"
#define FISBONE_IDENTIFIER "fisbone\0"
#define INDEX_IDENTIFIER "index\0"
#define FISBONE_SIZE 52
#define FISBONE_MESSAGE_HEADER_OFFSET 44
#define KEYPOINT_SIZE 20
#define SKELETON_VERSION(major, minor) (((major)<<16)|(minor))

const char* theora_message_headers = "Content-Type: video/theora\r\n"
									"Role: video/main\r\n"
									"Name: video_1\r\n";

const char* vorbis_message_headers = "Content-Type: audio/vorbis\r\n"
									"Role: audio/main\r\n"
									"Name: audio_1\r\n";

SkeletonEncoder::SkeletonEncoder(void)
{
}

SkeletonEncoder::~SkeletonEncoder(void)
{
}

void SkeletonEncoder::initSkeleton()
{
	ogg_packet op;
	size_t packet_size = 80;
	ogg_uint32_t version = SKELETON_VERSION(4, 0);

	memset (&op, 0, sizeof (op));

	//op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
	if (op.packet == NULL) return;

	memset (op.packet, 0, packet_size);
	memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
	write16le(op.packet+8, 4); /* version major */
	write16le(op.packet+10, 0); /* version minor */
	write64le(op.packet+12, (ogg_int64_t)0); /* presentation-time numerator */
	write64le(op.packet+20, (ogg_int64_t)1000); /* presentation-time denominator */
	write64le(op.packet+28, (ogg_int64_t)0); /* base-time numerator */
	write64le(op.packet+36, (ogg_int64_t)1000); /* base-time denominator */
	/* both the numerator are zero hence handled by the memset */
	write32le(op.packet+44, 0); /* UTC time, set to zero for now */

	/* Index start/end time, if unknown or non-indexed, will be -1. */
	if (version == SKELETON_VERSION(4,0)) {
		write64le(op.packet+64, m_fpGetNumber64(NUMBER64_FILE_LENGTH));
		write64le(op.packet+72, m_fpGetNumber64(NUMBER64_CONTENT_OFFSET));
	}
	op.b_o_s = 1; /* its the first packet of the stream */
	op.e_o_s = 0; /* its not the last packet of the stream */
	op.bytes = packet_size; /* length of the packet in bytes */

	m_lpHeaderPackets = createPacket(&op);
	_ogg_free (op.packet);
}

PacketList* SkeletonEncoder::addSkeleton()
{
	PacketList *ret = 0;
	ogg_packet op;
	size_t packet_size = 0;

	//////////////////////////////////////////////////////////////////////////
	// video
	memset (&op, 0, sizeof (op));
	packet_size = FISBONE_SIZE + strlen(theora_message_headers);
	//op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
	if (op.packet == NULL) return 0;

	memset (op.packet, 0, packet_size);
	/* it will be the fisbone packet for the theora video */
	memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
	write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
	write32le(op.packet+12, m_fpGetNumber32(NUMBER32_VIDEO_SERIAL_NO)); /* serialno of the theora stream */
	write32le(op.packet+16, 3); /* number of header packets */
	/* granulerate, temporal resolution of the bitstream in samples/microsecond */
	write64le(op.packet+20, m_fpGetNumber32(NUMBER32_VIDEO_FPS_NUMERTATOR)); /* granulrate numerator */
	write64le(op.packet+28, m_fpGetNumber32(NUMBER32_VIDEO_FPS_DENOMINATOR)); /* granulrate denominator */
	write64le(op.packet+36, 0); /* start granule */
	write32le(op.packet+44, 0); /* preroll, for theora its 0 */
	*(op.packet+48) = m_fpGetNumber32(NUMBER32_VIDEO_KEYFRAME_SHIFT); /* granule shift */
	/* message header fields */
	memcpy(op.packet+FISBONE_SIZE, theora_message_headers, strlen(theora_message_headers));

	op.b_o_s = 0;
	op.e_o_s = 0;
	op.bytes = packet_size; /* size of the packet in bytes */

	ret = createPacket(&op);
	_ogg_free (op.packet);

	memset (&op, 0, sizeof (op));
	packet_size = FISBONE_SIZE + strlen(vorbis_message_headers);
	//op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
	if (op.packet == NULL) return 0;

	memset (op.packet, 0, packet_size);
	/* it will be the fisbone packet for the vorbis audio */
	memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
	write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
	write32le(op.packet+12, m_fpGetNumber32(NUMBER32_AUDIO_SERIAL_NO)); /* serialno of the vorbis stream */
	write32le(op.packet+16, 3); /* number of header packet */
	/* granulerate, temporal resolution of the bitstream in Hz */
	write64le(op.packet+20, m_fpGetNumber32(NUMBER32_AUDIO_SAMPLE_RATE)); /* granulerate numerator */
	write64le(op.packet+28, (ogg_int64_t)1); /* granulerate denominator */
	write64le(op.packet+36, 0); /* start granule */
	write32le(op.packet+44, 2); /* preroll, for vorbis its 2 */
	*(op.packet+48) = 0; /* granule shift, always 0 for vorbis */
	memcpy(op.packet+FISBONE_SIZE, vorbis_message_headers, strlen(vorbis_message_headers));

	/* Important: Check the case of Content-Type for correctness */

	op.b_o_s = 0;
	op.e_o_s = 0;
	op.bytes = packet_size;

	ret->next = createPacket(&op);
	_ogg_free (op.packet);
}